package com.ruoyi.yljf.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BizCodeEnum;
import com.ruoyi.common.log.manager.AsyncManager;
import com.ruoyi.common.log.manager.factory.AsyncFactory;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.vx.MicroAppUtil;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.yljf.domain.BalanceDetail;
import com.ruoyi.yljf.domain.User;
import com.ruoyi.yljf.domain.dto.*;
import com.ruoyi.yljf.domain.vo.UserLoginVO;
import com.ruoyi.yljf.mapper.BalanceDetailMapper;
import com.ruoyi.yljf.mapper.UserMapper;
import com.ruoyi.yljf.service.IUserService;
import com.ruoyi.yljf.service.MSGService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;


/**
 * 用户管理Service业务层处理
 * 
 * @author metaee
 * @date 2025-01-07
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    
    @Resource
    private UserMapper userMapper;
    
    @Autowired
    private TokenService tokenService;
    
    @Autowired
    private MSGService msgService;
    
    @Autowired
    private MicroAppUtil microAppUtil;

    @Autowired
    private RedisCache redisCache;

    @Resource
    private BalanceDetailMapper balanceDetailMapper;

    @Resource
    private SysConfigMapper sysConfigMapper;

    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;
    
    /**
     * 查询用户管理列表
     * 
     * @param user 用户管理
     * @return 用户管理
     */
    @Override
    public List<User> selectUserList(User user) {
    	LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        if (StringUtils.isNotEmpty(user.getUserPhone())) {
			queryWrapper.eq(User::getUserPhone, user.getUserPhone());
		}
        if (StringUtils.isNotEmpty(user.getUserName())) {
			queryWrapper.like(User::getUserName, user.getUserName());
		}
        if (StringUtils.isNotEmpty(user.getUserAge())) {
			queryWrapper.eq(User::getUserAge, user.getUserAge());
		}
        if (StringUtils.isNotEmpty(user.getSex())) {
			queryWrapper.eq(User::getSex, user.getSex());
		}
        if (StringUtils.isNotEmpty(user.getUserIdentity())) {
			queryWrapper.eq(User::getUserIdentity, user.getUserIdentity());
		}
        return userMapper.selectList(queryWrapper);
    }

    /**
     * 用户注册
     * @param request
     */
    @Override
    public AjaxResult signIn(UserRegisterDTO request) {
        
        //封装用户
        User user = new User();
        BeanUtils.copyProperties(request,user);
        User user1 = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserPhone, user.getUserPhone())
        );
        if (ObjectUtils.isNotEmpty(user1)) {
//            throw new BizException(BizCodeEnum.USER_SIGN_ERROR);
            return AjaxResult.buildResult(BizCodeEnum.USER_SIGN_ERROR);

        }

        //密码加密
        user.setSalt("$1$" + StringUtils.getStringNumRandom(8));
        String cryptPwd = Md5Crypt.md5Crypt(request.getPassword().getBytes(), user.getSalt());
        user.setPassword(cryptPwd);

        int insert = userMapper.insert(user);
        //创建token并返回
        UserLoginVO result = getUserLoginVO(user, 3);
        log.info(" {}用户注册成功！", user.getUserPhone());

        //　用户注册后还需要创建支付,初始化用户支付信息
        
        return AjaxResult.success(result);
        
    }


    /**
     * 用户登录
     * @param request
     * @return
     */
    @Override
    public AjaxResult login(UserLoginDTO request) {

        //判断是否是VX登录直接
        if (StringUtils.isNotBlank(request.getVxCode())){
            
            //走VX登录
            List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("xv_open_id", request.getVxCode()));
            if (userList != null && userList.size() == 1){
                //1.获取用户信息
                User user = userList.get(0);

                UserLoginVO result = getUserLoginVO(user, 3);
                log.info("用户登录成功");
                

                return AjaxResult.success(result);
            } else {
                //如果没查询到用户，isRegister返回为0，跳转到注册

                log.info("登录失败");

                UserLoginVO result = UserLoginVO.builder().isRegister(1).build();
                return AjaxResult.success(result);

            }
            
        }else if (StringUtils.isNotBlank(request.getCaptcha())){
            //走常规登录
            List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("user_phone", request.getPhone()));

            //校验验证码
            boolean checkCode = msgService.checkCode(request.getPhone(), request.getCaptcha());

            //验证码错误
            if (!checkCode){
                return AjaxResult.buildResult(BizCodeEnum.CODE_ERROR);
            }
            
            //判断用户是否存在
            if (userList != null && userList.size() == 1){
                //1.获取用户信息
                User user = userList.get(0);
                
                return captchaLogin(user, request);
                
            } else {
                //如果没查询到用户，isRegister返回为0，跳转到注册

                log.info("登录失败");

                UserLoginVO result = UserLoginVO.builder().isRegister(1).build();
                return AjaxResult.success("跳转至注册",result);

            }
            
        }else if (StringUtils.isNotBlank(request.getPassword())){

            //走常规登录
            List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("user_phone", request.getPhone()));

            //判断用户是否存在
            if (userList != null && userList.size() == 1){
                //1.获取用户信息
                User user = userList.get(0);

                //密码登录
                return passwordLogin(user, request);
                    
            } else {
                //如果没查询到用户，isRegister返回为0，跳转到注册

                log.info("登录失败");

                UserLoginVO result = UserLoginVO.builder().isRegister(2).build();
                return AjaxResult.success("未查询到用户信息",result);

            }
            
        }

        log.warn("未输入验证码或者密码");
        return AjaxResult.error();
    }

    @NotNull
    private UserLoginVO getUserLoginVO(User user, int isRegister) {
        //封装用户信息,生成token
        String token = createToken(user);
        UserLoginVO result = BeanUtil.copyProperties(user, UserLoginVO.class);
        BeanUtil.copyProperties(user, UserLoginVO.class);
        result.setToken(token);
        result.setIsRegister(isRegister);
        return result;
    }

    /**
     * 绑定微信
     * @param request
     * @return
     */
    @Override
    public AjaxResult bindVX(UserBindVXDTO request) {
        String openId = microAppUtil.getOpenId(request.getCode());
        userMapper.update(null,new UpdateWrapper<User>()
                .eq("user_phone",request.getPhone())
                .set("wx_open_id",openId));
        
        log.info("WX绑定成功");
        return AjaxResult.success("绑定成功");
    }


    /**
     * 使用密码登录
     */
    private AjaxResult passwordLogin(User user, UserLoginDTO request){
        
        //用户传来的密码生成密文
        String salt = Md5Crypt.md5Crypt(request.getPassword().getBytes(), user.getSalt());
        
        if (salt.equalsIgnoreCase(user.getPassword())){

            //封装用户信息,生成token
            UserLoginVO result = getUserLoginVO(user, 1);


            log.info("用户登录成功");
            
            return AjaxResult.success(result);
        }
        
        return AjaxResult.buildResult(BizCodeEnum.USER_PWD_ERROR);
        
    }

    
    /**
     * 使用验证码登录
     * @param user
     */
    private AjaxResult captchaLogin(User user, UserLoginDTO request){

        
        //封装用户信息,生成token
        UserLoginVO result = getUserLoginVO(user, 3);


        log.info("用户登录成功");
        return AjaxResult.success(result);
        
    }

    /**
     * 根据 id 查找用户
     * @param userId
     * @return user
     */
    public User getUserById(Long userId){
        return userMapper.selectById(userId);
    }

    @Override
    public AjaxResult tokenLogin(UserLoginDTO dto) {
        try {
            Claims claims = parseToken(dto.getToken());
            // 解析对应的权限以及用户信息
            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
            String userKey = getTokenKey(uuid);
            LoginUser sysUser = redisCache.getCacheObject(userKey);
            User user = userMapper.selectById(sysUser.getUserId());
            UserLoginVO result = getUserLoginVO(user, 3);
            return AjaxResult.success(result);
        }catch (Exception e){
            return AjaxResult.buildResult(BizCodeEnum.TOKEN_ERROR);
        }
    }

    public AjaxResult loginOut(HttpServletRequest req) {
        LoginUser loginUser = tokenService.getLoginUser(req);
        if (StringUtils.isNotNull(loginUser))
        {
            String userName = loginUser.getUsername();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            log.info("{}用户退出登录成功",userName);
        }
        return AjaxResult.success("退出成功");
    }


    /**
     * 生成token
     */
    private String createToken(User user){
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getUserId());
        SysUser sysUser = new SysUser();
        sysUser.setUserId(user.getUserId());
        loginUser.setUser(sysUser);
        return tokenService.createToken(loginUser);
    }

    private Claims parseToken(String token)
    {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    private String getTokenKey(String uuid)
    {
        return CacheConstants.LOGIN_TOKEN_KEY + uuid;
    }

    @Override
    public Integer updateUserInfo(UserInfoDTO userInfoDTO) {
        User user= BeanUtil.copyProperties(userInfoDTO, User.class);
        user.setUserId(SecurityUtils.getUserId());
        return userMapper.updateById(user);
    }

    /**
     * 用户余额兑换   祈福币/祈智币
     * @param dto
     * @return
     */
    @Override
    public AjaxResult convert(ConvertDTO dto, HttpServletRequest req) {
        Long userId = tokenService.getLoginUser(req).getUserId();
        User user = userMapper.selectById(userId);

        double sum;
        String describe;
        double ratio;
        if(dto.getType().equals(1)) {
            // 查询祈福币兑换比例
            SysConfig qifuConfig = sysConfigMapper.checkConfigKeyUnique("qifu_ratio");
            if(qifuConfig == null) {
                ratio = 10;
            } else {
                String configValue = qifuConfig.getConfigValue();  // 余额 ：币 = configValue
                ratio = Double.parseDouble(configValue);
            }
            sum = dto.getNumber() / ratio;  // 所需余额
            if(user.getBalance().doubleValue() < sum) {
                return AjaxResult.error("余额不足");
            } else {
                user.setBalance(user.getBalance().subtract(new BigDecimal(sum)));
                user.setQifuCoin(user.getQifuCoin().add(new BigDecimal(dto.getNumber())));
                describe = "兑换祈福币";
            }
        } else if(dto.getType().equals(2)) {
            SysConfig qizhiConfig = sysConfigMapper.checkConfigKeyUnique("qizhi_ratio");
            if(qizhiConfig == null) {
                ratio = 10;
            } else {
                String configValue = qizhiConfig.getConfigValue();  // 余额 ：币 = configValue
                ratio = Double.parseDouble(configValue);
            }
            sum = dto.getNumber() / ratio;  // 所需余额
            if(user.getBalance().doubleValue() < sum) {
                return AjaxResult.error("余额不足");
            } else {
                user.setBalance(user.getBalance().subtract(new BigDecimal(sum)));
                user.setQizhiCoin(user.getQizhiCoin().add(new BigDecimal(dto.getNumber())));
                describe = "兑换祈智币";
            }
        } else {
            return AjaxResult.error("参数传入错误");
        }
        userMapper.updateById(user);
        BalanceDetail balanceDetail = new BalanceDetail();
        balanceDetail.setUserId(userId);
        balanceDetail.setDescribe(describe);
        balanceDetail.setDetail(String.valueOf(sum));
        balanceDetail.setCreatTime(new Date());
        balanceDetailMapper.insert(balanceDetail);
        return AjaxResult.success();
    }

}
